package model

import (
	"database/sql/driver"
	"encoding/json"
	"fmt"
	"time"
)

// OIDCClient OIDC客户端模型
type OIDCClient struct {
	BaseModel
	ClientID                string    `json:"client_id" gorm:"type:varchar(128);not null;uniqueIndex;comment:客户端ID"`
	ClientSecret            string    `json:"client_secret" gorm:"type:varchar(255);not null;comment:客户端密钥(哈希)"`
	ClientName              string    `json:"client_name" gorm:"type:varchar(128);not null;comment:客户端名称"`
	ClientType              string    `json:"client_type" gorm:"type:enum('confidential','public');default:'confidential';comment:客户端类型"`
	RedirectURIs            JSONArray `json:"redirect_uris" gorm:"type:json;not null;comment:重定向URI列表"`
	GrantTypes              JSONArray `json:"grant_types" gorm:"type:json;not null;comment:支持的授权类型"`
	ResponseTypes           JSONArray `json:"response_types" gorm:"type:json;not null;comment:支持的响应类型"`
	Scopes                  JSONArray `json:"scopes" gorm:"type:json;not null;comment:支持的作用域"`
	TokenEndpointAuthMethod string    `json:"token_endpoint_auth_method" gorm:"type:varchar(64);default:'client_secret_basic';comment:令牌端点认证方法"`
	AccessTokenTTL          int       `json:"access_token_ttl" gorm:"default:3600;comment:访问令牌有效期(秒)"`
	RefreshTokenTTL         int       `json:"refresh_token_ttl" gorm:"default:86400;comment:刷新令牌有效期(秒)"`
	IDTokenTTL              int       `json:"id_token_ttl" gorm:"default:3600;comment:ID令牌有效期(秒)"`
	Status                  int       `json:"status" gorm:"default:1;comment:状态:1-启用,0-禁用"`
	Description             string    `json:"description" gorm:"type:text;comment:描述"`
}

// OIDCAuthorizationCode 授权码模型
type OIDCAuthorizationCode struct {
	BaseModel
	Code                string    `json:"code" gorm:"type:varchar(128);not null;uniqueIndex;comment:授权码"`
	ClientID            string    `json:"client_id" gorm:"type:varchar(128);not null;comment:客户端ID"`
	UserName            string    `json:"user_name" gorm:"type:varchar(128);not null;comment:用户名"`
	UserID              uint64    `json:"user_id" gorm:"not null;comment:用户ID"`
	RedirectURI         string    `json:"redirect_uri" gorm:"type:varchar(512);not null;comment:重定向URI"`
	Scope               string    `json:"scope" gorm:"type:varchar(512);comment:作用域"`
	State               string    `json:"state" gorm:"type:varchar(128);comment:状态参数"`
	Nonce               string    `json:"nonce" gorm:"type:varchar(128);comment:随机数"`
	CodeChallenge       string    `json:"code_challenge" gorm:"type:varchar(128);comment:PKCE代码挑战"`
	CodeChallengeMethod string    `json:"code_challenge_method" gorm:"type:varchar(32);comment:PKCE代码挑战方法"`
	ExpiresAt           time.Time `json:"expires_at" gorm:"not null;comment:过期时间"`
	Used                bool      `json:"used" gorm:"default:false;comment:是否已使用"`
}

// OIDCAccessToken 访问令牌模型
type OIDCAccessToken struct {
	BaseModel
	Token     string    `json:"token" gorm:"type:varchar(512);not null;uniqueIndex;comment:访问令牌"`
	ClientID  string    `json:"client_id" gorm:"type:varchar(128);not null;comment:客户端ID"`
	UserID    uint64    `json:"user_id" gorm:"not null;comment:用户ID"`
	UserName  string    `json:"user_name" gorm:"type:varchar(128);not null;comment:用户名"`
	Scope     string    `json:"scope" gorm:"type:varchar(512);comment:作用域"`
	ExpiresAt time.Time `json:"expires_at" gorm:"not null;comment:过期时间"`
	Revoked   bool      `json:"revoked" gorm:"default:false;comment:是否已撤销"`
}

// OIDCRefreshToken 刷新令牌模型
type OIDCRefreshToken struct {
	BaseModel
	Token         string    `json:"token" gorm:"type:varchar(512);not null;uniqueIndex;comment:刷新令牌"`
	AccessTokenID uint64    `json:"access_token_id" gorm:"not null;comment:关联的访问令牌ID"`
	ClientID      string    `json:"client_id" gorm:"type:varchar(128);not null;comment:客户端ID"`
	UserID        uint64    `json:"user_id" gorm:"not null;comment:用户ID"`
	UserName      string    `json:"user_name" gorm:"type:varchar(128);not null;comment:用户名"`
	Scope         string    `json:"scope" gorm:"type:varchar(512);comment:作用域"`
	ExpiresAt     time.Time `json:"expires_at" gorm:"not null;comment:过期时间"`
	Revoked       bool      `json:"revoked" gorm:"default:false;comment:是否已撤销"`
}

// OIDCUserSession 用户会话模型
type OIDCUserSession struct {
	BaseModel
	SessionID      string     `json:"session_id" gorm:"type:varchar(128);not null;uniqueIndex;comment:会话ID"`
	UserID         uint64     `json:"user_id" gorm:"not null;comment:用户ID"`
	UserName       string     `json:"user_name" gorm:"type:varchar(128);not null;comment:用户名"`
	ClientSessions JSONObject `json:"client_sessions" gorm:"type:json;comment:客户端会话信息"`
	LoginTime      time.Time  `json:"login_time" gorm:"not null;comment:登录时间"`
	LastActivity   time.Time  `json:"last_activity" gorm:"not null;comment:最后活动时间"`
	ExpiresAt      time.Time  `json:"expires_at" gorm:"not null;comment:过期时间"`
	IPAddress      string     `json:"ip_address" gorm:"type:varchar(45);comment:IP地址"`
	UserAgent      string     `json:"user_agent" gorm:"type:text;comment:用户代理"`
	Status         int        `json:"status" gorm:"default:1;comment:状态:1-活跃,0-已结束"`
}

// OIDCScope 作用域模型
type OIDCScope struct {
	BaseModel
	ScopeName   string    `json:"scope_name" gorm:"type:varchar(64);not null;uniqueIndex;comment:作用域名称"`
	DisplayName string    `json:"display_name" gorm:"type:varchar(128);not null;comment:显示名称"`
	Description string    `json:"description" gorm:"type:text;comment:描述"`
	IsDefault   bool      `json:"is_default" gorm:"default:false;comment:是否为默认作用域"`
	Claims      JSONArray `json:"claims" gorm:"type:json;comment:包含的声明"`
	Status      int       `json:"status" gorm:"default:1;comment:状态:1-启用,0-禁用"`
}

// JSONArray 自定义JSON数组类型
type JSONArray []string

// Scan 实现 sql.Scanner 接口
func (j *JSONArray) Scan(value interface{}) error {
	if value == nil {
		*j = nil
		return nil
	}

	bytes, ok := value.([]byte)
	if !ok {
		return fmt.Errorf("cannot scan %T into JSONArray", value)
	}

	return json.Unmarshal(bytes, j)
}

// Value 实现 driver.Valuer 接口
func (j JSONArray) Value() (driver.Value, error) {
	if j == nil {
		return nil, nil
	}
	return json.Marshal(j)
}

// JSONObject 自定义JSON对象类型
type JSONObject map[string]interface{}

// Scan 实现 sql.Scanner 接口
func (j *JSONObject) Scan(value interface{}) error {
	if value == nil {
		*j = nil
		return nil
	}

	bytes, ok := value.([]byte)
	if !ok {
		return fmt.Errorf("cannot scan %T into JSONObject", value)
	}

	return json.Unmarshal(bytes, j)
}

// Value 实现 driver.Valuer 接口
func (j JSONObject) Value() (driver.Value, error) {
	if j == nil {
		return nil, nil
	}
	return json.Marshal(j)
}

// TableName 设置表名
func (OIDCClient) TableName() string {
	return "oidc_clients"
}

func (OIDCAuthorizationCode) TableName() string {
	return "oidc_authorization_codes"
}

func (OIDCAccessToken) TableName() string {
	return "oidc_access_tokens"
}

func (OIDCRefreshToken) TableName() string {
	return "oidc_refresh_tokens"
}

func (OIDCUserSession) TableName() string {
	return "oidc_user_sessions"
}

func (OIDCScope) TableName() string {
	return "oidc_scopes"
}
